package edit;

import java.util.ArrayList;
import java.util.Arrays;

import gui.GUI;
import gui.ModTreeTablePanel;
import skyproc.GRUP;
import skyproc.MajorRecord;
import skyproc.MajorRecordNamed;

@SuppressWarnings("rawtypes")
public class GRUPHolder implements HolderInterface {

	private GRUP<?> grup;
	
	 /////////////////////////////////////////////////////////////////////////
	// Using static variable to hold the filtered and sorted records. This
	// isn't ideal, but the database isn't cached in Holders, so it's the
	// simplest solution. If it ever is, then this should be "unstatic'd".
	//
	// As it stands now, this Collection is updated in the getChildCount()
	// method (eww...), since, as far as I know, that method will be called
	// before the getChildAt() method (so it is kept up-to-date when reading
	// new GRUPs.
	//
	// On the bright side, having it as a static variable is more efficient,
	// memory-wise.
	//
	private static ArrayList<MajorRecord> display;
	//////////////////////////////////////////////////////////////////////////
	
 	 //////////////////////////////////////////
	// Filter stuff
	public enum FilterType {
		NONE, FORM, EDID, NAME
	};
	public  static FilterType fType  = FilterType.NONE;
	public  static String     filter = "";
	///////////////////////////////////////////
	
	 //////////////////////////////////////////
	// Sort stuff
	public enum SortDirection {
		NONE, ASCENDING, DESCENDING
	};
	public static SortDirection sDirection = SortDirection.NONE;
	
	public enum SortType {
		NONE, FORM, EDID, NAME
	};
	public static SortType sType = SortType.NONE;
	///////////////////////////////////////////
	
	/**
	 * Constructor.
	 * 
	 * @param grup Object held.
	 */
	public GRUPHolder(GRUP grup) {
		this.grup = grup;
	}
	
	

	@Override
	public String getDescription() {
		return grup.getContainedType().name();
	}

	@Override
	public Object getValueAt(int index) {
		return null;
	}

	@Override
	public boolean isLeaf() {
		return getChildCount() == 0;
	}

	@Override
	public Object getChild(Object parent, int index) {
		
		return new MajorRecordHolderLeaf( display.get(index) );
	}

	@Override
	public int getChildCount() {
		// Filter and sort records
		filter();
		sort();
		
		return display.size();
	}

	@Override
	public int getIndexOfChild(Object parent, Object child) {

		return display.indexOf(child);
	}

	@Override
	public Object getHeldObject() {
		return grup;
	}

	private void filter() {
		display = new ArrayList<MajorRecord>(grup.numRecords());
		ArrayList<? extends MajorRecord> tmp = grup.getRecords();
		
		if( !filter.equals("") ) {
			
			for(MajorRecord r : tmp) {
				switch(fType) {
				case FORM:
					if( r.getFormStr().contains(filter) ) {
						display.add(r);
					}
					break;
					
				case EDID:
					if( r.getEDID().contains(filter) ) {
						display.add(r);
					}
					break;
					
				case NAME:
					if(
							r instanceof MajorRecordNamed
							&&
							((MajorRecordNamed)r).getName().contains(filter)
					) {
						display.add(r);
					}
					break;
				}	
			}
		}
		else {
			for(MajorRecord r : tmp)
				display.add(r);
		}
	}
	
	private void sort() {
		MajorRecord[] data = new MajorRecord[ display.size() ];
		display.toArray(data);
		
		switch(sType) {
		case FORM:
			sortByFormID(data, 0, data.length-1);
			break;
			
		case EDID:
			sortByEditorID(data, 0, data.length-1);
			break;
			
		case NAME:
			sortByName(data, 0, data.length-1);
			break;
		}
		display = new ArrayList<MajorRecord>(Arrays.asList(data));
	}
	
	private void sortByFormID(MajorRecord[] data, int a, int b) {
		if( a >= b)
		{
			return;
		}
		
		MajorRecord pivot = data[b];
		int left  = a;
		int right = b - 1;
		
		while(left <= right)
		{
			while(
					left <= right
					&&
					data[left].getForm().compareTo(pivot.getForm()) <= 0
			)
			{
				++left;
			}
			while(
					right >= left
					&&
					data[right].getForm().compareTo(pivot.getForm()) >= 0
			)
			{
				--right;
			}
			if(left <= right)
			{
				MajorRecord tmp = data[left];
				data[left]  = data[right];
				data[right] = tmp;
			}
		}
		MajorRecord tmp = data[left];
		data[left] = data[b];
		data[b]    = tmp;

		sortByFormID( data, a, (left-1) );
		sortByFormID( data, (left+1), b );
	}
	
	private void sortByEditorID(MajorRecord[] data, int a, int b) {
		if( a >= b)
		{
			return;
		}
		
		MajorRecord pivot = data[b];
		int left  = a;
		int right = b - 1;
		
		while(left <= right)
		{
			while(
					left <= right
					&&
					data[left].getEDID().compareToIgnoreCase(pivot.getEDID()) <= 0
			)
			{
				++left;
			}
			while(
					right >= left
					&&
					data[right].getEDID().compareToIgnoreCase(pivot.getEDID()) >= 0
			)
			{
				--right;
			}
			if(left <= right)
			{
				MajorRecord tmp = data[left];
				data[left]  = data[right];
				data[right] = tmp;
			}
		}
		MajorRecord tmp = data[left];
		data[left] = data[b];
		data[b]    = tmp;

		sortByEditorID( data, a, (left-1) );
		sortByEditorID( data, (left+1), b );
	}
	
	private void sortByName(MajorRecord[] data, int a, int b) {
		if( a >= b)
		{
			return;
		}
		
		MajorRecord pivot = data[b];
		int left  = a;
		int right = b - 1;
		
		while(left <= right)
		{
			while(
					left <= right
					&&
					data[left].getName().compareToIgnoreCase(pivot.getName()) <= 0
			)
			{
				++left;
			}
			while(
					right >= left
					&&
					data[right].getName().compareToIgnoreCase(pivot.getName()) >= 0
			)
			{
				--right;
			}
			if(left <= right)
			{
				MajorRecord tmp = data[left];
				data[left]  = data[right];
				data[right] = tmp;
			}
		}
		MajorRecord tmp = data[left];
		data[left] = data[b];
		data[b]    = tmp;

		sortByName( data, a, (left-1) );
		sortByName( data, (left+1), b );
	}
}
